

import java.util.ArrayList;
import java.util.List;

/**
 * This parameterized class defines a Constraint in a Constraint Satisfaction Problem
 *
 * @param <Type> refers to the type of values that the CSP variables will be assigned.
 * Such a type will be specified at some later point either by subclassing or at runtime when instantiating
 */
public abstract class Constraint<Type> {
	
	/**
	 * String specifying the constraint's name
	 */
	private String name;
	
	/**
	 * List<Variable<Type>> containing the variables involved in the constraint.
	 */
	private List<Variable<Type>> variables;
	
	/**
	 * Constructor method
	 * @param name String specifying the constraint's name.
	 * @param variables List<Variable<Type>> containing the variables involved in the constraint.
	 */
	public Constraint(String name, List<Variable<Type>> variables){
		this.name = name;
		this.variables = new ArrayList<Variable<Type>>();		
		this.variables.addAll(variables);
	}

	/**
	 * returns the constraint's name.
	 * @return String specifying the constraint's name.
	 */
	public String getName() {
		return name;
	}

	/**
	 * updates the constraint's name.
	 * @param name String specifying the constraint's new name.
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * Adds a new variable to the list of variables involved in the constraint.
	 * @param variable Variable<Type> specifying the new variable to add to this constraint.
	 */
	public void addVariable(Variable<Type> variable) {
		if (variable != null && !this.variables.contains(variable)) {
			this.variables.add(variable);
		}
	}
	
	/**
	 * Adds a list of variables to the list of variables involved in the constraint.
	 * @param variables ArrayList<Variable<Type>> containing the list of variables to add to this constraint.
	 */
	public void addVariables(ArrayList<Variable<Type>> variables) {
		for (Variable<Type> variable: variables) {
			if (variable != null && !this.variables.contains(variable)) {			
				this.addVariable(variable);
			}
		}
	}

	/**
	 * returns the list of variables involved in this constraint.
	 * @return List<Variable<Type>> containing the list of variables involved in this constraint.
	 */
	public List<Variable<Type>> getVariables() {
		return variables;
	}

	/**
	 * Checks whether the value to be assigned to a variable satisfies the constraint.
	 * This method ought to check whether assigning the value to the variable is consistent with 
	 * the assignments made so far.
	 * @param variable Variable<Type> specifying the variable to be assigned next.
	 * @param value Type specifying the value to be assigned to the variable
	 * @return
	 * 	<ul>
	 * 		<li><b>true</b> - If assigning the value to the variable is consistent.	
	 * 		<li><b>false</b> - If assigning the value to the variable is inconsistent.
	 * </ul>
	 */
	public abstract boolean isSatisfied(Variable<Type> variable, Type value);
}